package 集合;

/*
【iterable接口】
整个接口框架关系如下（来自百度百科）：

iterable接口其实是java集合大家庭的最顶级的接口之一了，实现这个接口，可以视为拥有了获取迭代器的能力。Iterable接口出现在JDK1.5，那个时候只有iterator()方法，
主要是定义了迭代集合内元素的规范。
实现了Iterable接口，我们可以使用增强的for循环，即

for(String str : lists){
     System.out.println(str);
}
1. 内部定义的方法
java集合最源头的接口，实现这个接口的作用主要是集合对象可以通过迭代器去遍历每一个元素。

源码如下：

//一、返回一个内部元素为T类型的迭代器（JDK1.5只有这个接口）
Iterator<T> iterator();

//二、遍历内部元素，action意思为动作，指可以对每个元素进行操作（JDK1.8添加）
default void forEach(Consumer<? super T> action) {}

//三、创建并返回一个可分割迭代器（JDK1.8添加），分割的迭代器主要是提供可以并行遍历元素的迭代器，可以适应现在cpu多核的能力，加快速度。
default Spliterator<T> spliterator() {
    return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
从上面可以看出，foreach迭代以及可分割迭代，都加了default关键字，这个是Java 8 新的关键字，以前接口的所有接口，具体子类都必须实现，而对于deafult关键字标识的方
法，其子类可以不用实现，这也是接口规范发生变化的一点。
下面我们分别展示三个接口的调用：
*/
/*
1.1 iterator()方法
iterator()方法，是接口中的核心方法,主要是获取迭代器，获取到的iterator有next(),hasNext(),remove()等方法。

public interface Iterator<E> {
	//1.
   boolean hasNext();
   //2.
   E next();
   //3.
   default void remove() {
       throw new UnsupportedOperationException("remove");
   }
   //4.
   default void forEachRemaining(Consumer<? super E> action) {
       Objects.requireNonNull(action);
       while (hasNext())
           action.accept(next());
   }
}

public static void iteratorHasNext(){
    List<String> list=new ArrayList<String>();//转成List即Collention类实现Interable接口
    list.add("Jam");
    list.add("Jane");
    list.add("Sam");
    // 返回迭代器
    Iterator<String> iterator=list.iterator();
    // hashNext可以判断是否还有元素
    while(iterator.hasNext()){
        //next()作用是返回当前指针指向的元素,之后将指针移向下个元素
        System.out.println(iterator.next());
    }
}
当然也可以使用for-each loop方式遍历

for (String item : list) {
    System.out.println(item);
}
但是实际上，这种写法在class文件中也是会转成迭代器形式，这只是一个语法糖。class文件如下：
*/
/*
public class IterableTest {
    public IterableTest() { }
    public static void main(String[] args) {
        iteratorHasNext();
    }
    public static void iteratorHasNext() {
        List<String> list = new ArrayList();
        list.add("Jam");
        list.add("Jane");
        list.add("Sam");
        Iterator<String> iterator = list.iterator();
        Iterator var2 = list.iterator();
        while(var2.hasNext()) {
            String item = (String)var2.next();
            System.out.println(item);
        }
    }
}
需要注意的一点是，迭代遍历的时候，如果删除或者添加元素，都会抛出修改异常，这是由于快速失败【fast-fail】机制。

    public static void iteratorHasNext(){
        List<String> list=new ArrayList<String>();
        list.add("Jam");
        list.add("Jane");
        list.add("Sam");
        for (String item : list) {
            if(item.equals("Jam")){
                list.remove(item);
            }
            System.out.println(item);
        }
    }
从下面的错误我们可以看出，第一个元素是有被打印出来的，也就是remove操作是成功的，只是遍历到第二个元素的时候，迭代器检查，发现被改变了，所以抛出了异常。

Jam
Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
 at java.util.ArrayList$Itr.next(ArrayList.java:859)
 at IterableTest.iteratorHasNext(IterableTest.java:15)
 at IterableTest.main(IterableTest.java:7)

1.2 forEach()方法
其实就是把对每一个元素的操作当成了一个对象传递进来，对每一个元素进行处理。

    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
当然像ArrayList自然也是有自己的实现的，那我们就可以使用这样的写法,简洁优雅。forEach方法在java8中参数是java.util.function.Consumer,可以称为消费行为或者
说动作类型。

list.forEach(x -> System.out.print(x));
同时，我们只要实现Consumer接口，就可以自定义动作，如果不自定义，默认迭代顺序是按照元素的顺序。

public class ConsumerTest {
    public static void main(String[] args) {
        List<String> list=new ArrayList<String>();
        list.add("Jam");
        list.add("Jane");
        list.add("Sam");
        MyConsumer myConsumer = new MyConsumer();
        Iterator<String> it = list.iterator();
        list.forEach(myConsumer);
    }
    static class MyConsumer implements Consumer<Object> {
        @Override
        public void accept(Object t) {
            System.out.println("自定义打印：" + t);
        }
    }
}
输出的结果：

自定义打印：Jam
自定义打印：Jane
自定义打印：Sam


1.3 spliterator()方法
这是一个为了并行遍历数据元素而设计的迭代方法，返回的是Spliterator，是专门并行遍历的迭代器。以发挥多核时代的处理器性能，java默认在集合框架中提供了一个默认
的Spliterator实现，底层也就是Stream.isParallel()实现的，我们可以看一下源码：
public interface Collection<E> extends Iterable<E> {
	...
// stream使用的就是spliterator
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }
    public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
        Objects.requireNonNull(spliterator);
        return new ReferencePipeline.Head<>(spliterator,
                                            StreamOpFlag.fromCharacteristics(spliterator),
                                            parallel);
    }
    

//default Spliterator<T> spliterator() {
//        return Spliterators.spliteratorUnknownSize(iterator(), 0);
//    }    
    
    
使用的方法如下：
*/
import java.util.Spliterator;
import java.util.Arrays;
import java.util.List;

public class Iterator和Iterable {
	public static void main(String[] args) {
		List<String> list = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
		// 获取可迭代器
		Spliterator<String> spliterator = list.spliterator();
		// 一个一个遍历
		System.out.println("tryAdvance: ");
		spliterator.tryAdvance(item -> System.out.print(item + " "));
		spliterator.tryAdvance(item -> System.out.print(item + " "));
		spliterator.tryAdvance(item -> System.out.print(item + " "));
		spliterator.tryAdvance(item -> System.out.print(item + " "));
		System.out.println("\n-------------------------------------------");

		// 依次遍历剩下的
		System.out.println("forEachRemaining: ");
		spliterator.forEachRemaining(item -> System.out.print(item + " "));
		System.out.println("\n------------------------------------------");

		// spliterator1:0~10
		Spliterator<String> spliterator1 = list.spliterator();
		
		// spliterator1:6~10 spliterator2:0~5
		Spliterator<String> spliterator2 = spliterator1.trySplit();
		
		// spliterator1:8~10 spliterator3:6~7
		Spliterator<String> spliterator3 = spliterator1.trySplit();
		System.out.println("spliterator1: ");
		spliterator1.forEachRemaining(item -> System.out.print(item + " "));
		System.out.println("\n------------------------------------------");
		System.out.println("spliterator2: ");
		spliterator2.forEachRemaining(item -> System.out.print(item + " "));
		System.out.println("\n------------------------------------------");
		System.out.println("spliterator3: ");
		spliterator3.forEachRemaining(item -> System.out.print(item + " "));
	}
}
/*
tryAdvance() 一个一个元素进行遍历  boolean tryAdvance(Consumer<? super T> action)
forEachRemaining() 顺序地分块遍历  void forEachRemaining(Consumer<? super T> action)
trySplit()进行分区形成另外的 Spliterator，使用在并行操作中，分出来的是前面一半，就是不断把前面一部分分出来  Spliterator<T> trySplit()
结果如下：

tryAdvance: 
1 2 
-------------------------------------------
forEachRemaining: 
3 4 5 6 7 8 9 10 
------------------------------------------
spliterator1: 
8 9 10 
------------------------------------------
spliterator2: 
1 2 3 4 5 
------------------------------------------
spliterator3: 
6 7 
还有一些其他的用法在这里就不列举了，主要是trySplit()之后，可以用于多线程遍历。理想的时候，可以平均分成两半，有利于并行计算，但是不是一定平分的。
*/
/*
Java 中的自定义 Iterable 和 Iterator

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;

//You will inherit it
//Define Custom Iterable
public class IteratorAndIterable<T> implements Iterable<T>{
	//An array list (setL: setlist)
	private List<T> setL = new ArrayList<>();
	//Get value from the List
	public void add(T getback) {
		setL.add(getback);
	}
	//Define Iterator to get your iterable objects
	public Iterator<T> iterator() {
		return new myCi<T>(setL);
	}
	// Your custom iterator overrides Iterator
	public class myCi<E> implements Iterator<E> {
		//For a condition to avoid exception later
		int SP = 0;
		//Custom Array List
		List<E> CAL;
		public myCi(List<E> CAL) {
			this.CAL = CAL;
		}
		//Check the iterator values
		public boolean hasNext() {
			if(CAL.size() >= SP +1) {
				// Remember SP = 0? To avoid exception
				//If hasNext() has value, it returns true
				return true;
			}
			return false;
		}
		//Use next() to get the token that hasNext() just passed
		//No need to use default values, make use of the your custom <E>
		public E next() {
			//Get token and store it into getback
			E getback = CAL.get(SP);
			//You can do anything with this loop now
			SP ++;
			// return getback instead of deafault value (Now check line number 122) It will be clear
			return getback;
		}
		public void remove() {

		}
	}
}
*/

